// Managed.h

#pragma once

#define overload new

#if defined(DEBUG) | defined(_DEBUG)
//#include "crtdbg.h"
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#endif

#using <mscorlib.dll>

using namespace System;
using namespace System::Collections;
using namespace System::Runtime::InteropServices;

//UnManaged::System::NullPtr
#pragma unmanaged

namespace UnManaged
{
#	include <System.hpp>
#	include <Events.hpp>
#	include <Module.hpp>

#	include <IDK.hpp>

#	include <Timer.hpp>

#	include <Camera.hpp>
#	include <ThirdPersonCamera.hpp>
#	include <ModuleManager.hpp>
#	include <GameRenderTechnique.hpp>
}

#pragma managed

#	include <ManagedMath.hpp>
#	include <ManagedObject.hpp>
#	include <ManagedArray.hpp>
#	include <ManagedList.hpp>

namespace IDK
{
	//Adaptor
	template<typename RetVal, typename T>
	RetVal^ ConvertToManaged(T ptr)
	{
		if(ptr != UnManaged::System::NullPtr)
		{
			return gcnew RetVal(ptr.GetUnmanagedPointer());
		}
		return nullptr; 
	}

	//StringAdaptor
	class StringAdaptor
	{
	public:
		StringAdaptor(String^ str)
		{
			mSelf = (char*)Marshal::StringToHGlobalAnsi(str).ToPointer();
		}

		~StringAdaptor(void)
		{
			Marshal::FreeHGlobal(System::IntPtr(mSelf));
		}

		UnManaged::System::String Get(void)
		{
			return UnManaged::System::String(mSelf);
		}
	private:
		char* mSelf;
	};

	//Module
	public ref class Module : public ManagedObject
	{
		typedef UnManaged::System::Module::IModule Self;
	public:
		Module(Self* self) : ManagedObject(mSelf = self)
		{}

		Self* GetSelf(void) overload { return mSelf; }
	protected:
		Self* mSelf;
	};

	//HandlePtr
	public ref class HandlePtr : public ManagedObject 
	{
		typedef UnManaged::System::THandlePtr Self;
	public:
		HandlePtr(Self* self) : ManagedObject(mSelf = self)
		{}

		Self* GetSelf(void) overload { return mSelf; }
	protected:
		Self* mSelf;
	};

	//Displayable
	public ref class Displayable : public ManagedObject
	{
	public:
		typedef UnManaged::IDK::IDisplayable Self;

		Displayable(Self* self) : ManagedObject(mSelf = self)
		{}
		Self* GetSelf(void) overload { return mSelf; }
	private:
		Self* mSelf;
	};

	//Renderable
	public ref class Renderable : public Displayable
	{
	public:
		typedef UnManaged::IDK::IRenderable Self;

		Renderable(Self* self) : Displayable(mSelf = self)
		{}
		Self* GetSelf(void) overload { return mSelf; }
	private:
		Self* mSelf;
	};

	//RenderTexture
	public ref class Texture : public ManagedObject
	{
		typedef UnManaged::IDK::ITexture Self;
	public:

		[Flags]
		enum struct Format
		{
				RGBA = Self::Format::RGBA,
				RGB_DXT1 = Self::Format::RGB_DXT1,
				RGBA_DXT1 = Self::Format::RGBA_DXT1,
				RGBA_DXT3 = Self::Format::RGBA_DXT3,
				RGBA_DXT5 = Self::Format::RGBA_DXT5,
				Max = Self::Format::MAX
		};

		[Flags]
		enum struct PixelType
		{
				ByteRGBA8 = Self::PixelType::ByteRGBA8,
				FloatRGBA16 = Self::PixelType::FloatRGBA16,
				FloatRGBA32 = Self::PixelType::FloatRGBA32,
				MAX = Self::PixelType::MAX
		};

		Texture(Self* self) : ManagedObject(mSelf = self)
		{}

		Self* GetSelf(void) overload { return mSelf; }
	private:
		Self* mSelf;
	};

	//ShaderProgram
	public ref class ShaderProgram : public ManagedObject
	{
		typedef UnManaged::IDK::IShaderProgram Self;
	public:
		ref class Parameter : public ManagedObject
		{
			typedef UnManaged::IDK::IShaderProgram::IParameter Self;
		public:
			[Flags]
			enum struct Declaration
			{
				None = 0,
				VertexPosition,
				VertexNormal,
				VertexTangent,
				VertexTexCoord,
				MatrixProjection,
				MatrixView,
				MatrixWorld,
				MatrixViewInverse,
				Texture0,
				Texture1,
				Texture2,
				Texture3,
				Texture4,
				Constant2f,
				Constant3f,
				Constant44f,
				MAX
			};

			[Flags]
			enum struct Type
			{
				VertexAttribute = 0,
				ConstantParameter
			};

			Parameter(Self* self) : ManagedObject(mSelf = self)
			{}
		private:
			Self* mSelf;
		};

		ShaderProgram(Self* self) : ManagedObject(mSelf = self)
		{}

		Self* GetSelf(void) overload { return mSelf; }

		void AddParameter(Parameter::Type typ, Parameter::Declaration decl, String^ name)
		{
			StringAdaptor string(name);
			mSelf->AddParameter(UnManaged::IDK::IShaderProgram::IParameter::Type::Enum(typ),
				 UnManaged::IDK::IShaderProgram::IParameter::Declaration::Enum(decl),
				string.Get());
		}

		void AddParameterData(Parameter::Type typ, Parameter::Declaration decl, String^ name, HandlePtr^ handle)
		{
			StringAdaptor string(name);
			mSelf->AddParameter(UnManaged::IDK::IShaderProgram::IParameter::Type::Enum(typ),
				 UnManaged::IDK::IShaderProgram::IParameter::Declaration::Enum(decl),
				string.Get(), handle->GetSelf());
		}
	private:
		Self* mSelf;
	};

	//RenderTexture
	public ref class RenderTexture : public Texture
	{
		typedef UnManaged::IDK::IRenderTexture Self;
	public:
		RenderTexture(Self* self) : Texture(mSelf = self)
		{}

		Self* GetSelf(void) overload { return mSelf; }
	private:
		Self* mSelf;
	};

	//RenderTarget
	public ref class RenderTarget : public ManagedObject
	{
		typedef UnManaged::IDK::IRenderTarget Self;
	public:
		RenderTarget(Self* self) : ManagedObject(mSelf = self)
		{}

		void AttachTexture(RenderTexture^ rtexture)
		{
			mSelf->AttachTexture(rtexture->GetSelf());
		}
		Self* GetSelf(void) overload { return mSelf; }
	private:
		Self* mSelf;
	};


	public ref class IndexVertexBuffer : public ManagedObject
	{
		typedef UnManaged::IDK::IIndexVertexBuffer Self;
	public:
		IndexVertexBuffer(Self* self) : ManagedObject(mSelf = self)
		{}

		Self* GetSelf(void) overload { return mSelf; }

		int GetIndexCount()
		{
			return mSelf->GetIndexCount();
		}

		void GetIndexData(array<short>^ data)
		{
			//bind data
			const short* ptr = static_cast<const short*>(mSelf->GetIndexData()->GetPointer());
			for each(short% it in data)
			{
				it = *ptr++;
			}
		}

		void GetVertexData(array<Vector3>^ data)
		{
			const UnManaged::Math::Vector3* ptr = static_cast<const UnManaged::Math::Vector3*>(mSelf->GetVertexData()->GetPointer());
			for each(Vector3% it in data)
			{
				it = Vector3(*ptr++);
				//TODO:: Skip by semantic
				*ptr++; // skip normal
				*ptr++; // skip tangent
				*ptr++; // skip texcoord
			}
		}

		int GetVertexCount()
		{
			return mSelf->GetVertexCount();
		}
	private:
		Self* mSelf;
	};

	//Mesh
	public ref class Mesh : public ManagedObject
	{
		typedef UnManaged::IDK::IMesh Self;
	public:
		Mesh(Self* self) : ManagedObject(mSelf = self)
		{}

		Self* GetSelf(void) overload { return mSelf; }
	private:
		Self* mSelf;
	};

	//Material
	public ref class Material : public ManagedObject
	{
		typedef UnManaged::IDK::IMaterial Self;
	public:
		[Flags]
		enum struct TextureMode
		{
				Decal = 0,
				Normal,
				Specular,
				Tex3,
				Tex4,
				Tex5,
				MAX
		};

		Material(Self* self) : ManagedObject(mSelf = self)
		{}

		void SetTexture(TextureMode mode, Texture^ texture)
		{
			mSelf->SetTexture((Self::TextureMode::Enum)mode, texture->GetSelf());
		}

		void SetShaderProgram(ShaderProgram^ shaderProgram)
		{
			mSelf->SetShaderProgram(shaderProgram->GetSelf());
		}
		Self* GetSelf(void) overload { return mSelf; }
	private:
		Self* mSelf;
	};

	//SceneNode
	public ref class SceneNode : public Displayable
	{
	public:
		typedef UnManaged::IDK::ISceneNode Self;
		//Transformation
		ref class Transformation : public ManagedObject
		{
			typedef UnManaged::IDK::ISceneNode::ITransformation Self;
		public:
			Transformation(Self* self) : ManagedObject(mSelf = self)
			{}

			void Translate(Vector3 move)
			{
				mSelf->Translate(move.GetSelf());
			}

			AABBox GetOriginalAABBox()
			{
				return AABBox(mSelf->GetOriginalAABBox());
			}

			void Rotate(Quaternion rot)
			{
				mSelf->Rotate(rot.GetSelf());
			}

			Quaternion GetLocalOrientation(void)
			{
				return Quaternion(mSelf->GetLocalOrientation());
			}

			void SetLocalOrientation(Quaternion rot)
			{
				mSelf->SetLocalOrientation(rot.GetSelf());
			}

			Quaternion GetWorldOrientation(void)
			{
				return Quaternion(mSelf->GetWorldOrientation());
			}

			void SetLocalPosition(Vector3 pos)
			{
				mSelf->SetLocalPosition(pos.GetSelf());
			}

			Vector3 GetLocalPosition(void)
			{
				return Vector3(mSelf->GetLocalPosition());
			}

			Vector3 GetWorldPosition(void)
			{
				return Vector3(mSelf->GetWorldPosition());
			}

			Vector3 GetLocalScale(void)
			{
				return Vector3(mSelf->GetLocalScale());
			}

			Vector3 GetWorldScale(void)
			{
				return Vector3(mSelf->GetWorldScale());
			}

			AABBox GetTransformAABBox(void)
			{
				return AABBox(mSelf->GetTransformAABBox());
			}

			void SetTransform(Quaternion q, Vector3 pos)
			{
				mSelf->SetTransform(q.GetSelf(), pos.GetSelf());
			}

			Self* GetSelf(void) overload { return mSelf; }
			//void Ro
		private:
			Self* mSelf;
		};

		SceneNode(Self* self) : Displayable(mSelf = self)
		{
			//reset chache values
			mChacheTransformation = nullptr;
		}

		String^ GetName(void) 
		{
			return gcnew String(mSelf->GetName()->Chars());
		}

		void AddRenderable(Renderable^ disp)
		{
			mSelf->AddRenderable(disp->GetSelf());
		}

		typedef ManagedArray<Renderable, Renderable::Self> Renderables;

		Renderables^ GetRenderables()
		{
			return gcnew Renderables(mSelf->GetRenderables().GetUnmanagedPointer());
		}

		SceneNode::Transformation^ GetTransformation(void)
		{
			if(mChacheTransformation == nullptr)
			{
				return mChacheTransformation = ConvertToManaged<Transformation>(mSelf->GetTransformation());
			}
			else
			{
				return mChacheTransformation;
			}
		}

		void MakeTransformation(SceneNode::Transformation^ transCopy)
		{
			mSelf->MakeTransformation(transCopy->GetSelf());
		}

		void MakeTransformation(Vector3 pos, Quaternion rot, AABBox aabbox, Vector3 scale)
		{
			mChacheTransformation = nullptr;
			mSelf->MakeTransformation(pos.GetSelf(), rot.GetSelf(), aabbox.GetSelf(), scale.GetSelf());
		}

		property bool Visible
		{
			bool get()
			{
				return mSelf->IsVisible();
			}
			void set(bool value)
			{
				mSelf->SetVisible(value);
			}
		}

		Self* GetSelf(void) overload { return mSelf; }
	private:
		SceneNode::Transformation^ mChacheTransformation;
		Self* mSelf;
	};

	//SceneObject
	public ref class SceneObject : public Renderable
	{
		typedef UnManaged::IDK::ISceneObject Self;
	public:
		SceneObject(Self* self) : Renderable(mSelf = self)
		{}

		void SetMesh(Mesh^ mesh)
		{
			mSelf->SetMesh(mesh->GetSelf());
		}

		void SetMaterial(Material^ material)
		{
			mSelf->SetMaterial(material->GetSelf());
		}
	private:
		Self* mSelf;
	};

	public ref class SceneNodesList : public ManagedTreeList<SceneNode, SceneNode::Self>
	{
	public:
		SceneNodesList(Self* self) : ManagedTreeList(mSelf = self)
		{}

		ref class NodeItem : public Item
		{
		public:
			NodeItem(Self* self) : Item(self)
			{}

			SceneNode^ Current() overload
			{
				return Item::Current();
			}

			SceneNodesList^ GetChildren() overload
			{
				return gcnew SceneNodesList(Item::GetChildren()->GetSelf());
			}
		};

		virtual Item^ Get(int index) override
		{
			return gcnew NodeItem(mSelf->Get(index).GetUnmanagedPointer());
		}

	private:
		Self* mSelf;
	};

	//Scene
	public ref class Scene : public ManagedObject
	{
		typedef UnManaged::IDK::IScene Self;
	public:
		Scene(Self* self) : ManagedObject(mSelf = self)
		{}

		Self* GetSelf(void) overload { return mSelf;  }


		SceneNodesList^ GetRootNodes()
		{
			return gcnew SceneNodesList(mSelf->GetRootNodes().GetUnmanagedPointer());
		}

		SceneNode^ GetNode(String^ name)
		{
			StringAdaptor string(name);
			return gcnew SceneNode(mSelf->GetNode(string.Get()).GetUnmanagedPointer());
		}

		void Update()
		{
			mSelf->Update();
		}

		void Clear(void)
		{
			mSelf->Clear();
		}

		SceneNode^ GetNodeByRay(SceneNode^ container, Vector3 rayStart, Vector3 rayDir)
		{
			return ConvertToManaged<SceneNode>(mSelf->GetNodeByRay(container->GetSelf(), UnManaged::System::Math::Ray(rayStart.GetSelf(), rayDir.GetSelf())));
		}

		SceneNode^ AddNode(String^ name, SceneNode^ parent)
		{
			StringAdaptor string(name);
			if(parent == nullptr)
			{
				return gcnew SceneNode(mSelf->AddNode(string.Get(), UnManaged::System::NullPtr).GetUnmanagedPointer());
			}
			else
			{
				return gcnew SceneNode(mSelf->AddNode(string.Get(), parent->GetSelf()).GetUnmanagedPointer());
			}
		}

		SceneNode^ AddNode(SceneNode^ node, SceneNode^ parent)
		{
			if(parent == nullptr)
			{
				return gcnew SceneNode(mSelf->AddNode(node->GetSelf(), UnManaged::System::NullPtr).GetUnmanagedPointer());
			}
			else
			{
				return gcnew SceneNode(mSelf->AddNode(node->GetSelf(), parent->GetSelf()).GetUnmanagedPointer());
			}
		}
	private:
		Self* mSelf;
	};

	//Camera
	public ref class Camera : public Displayable
	{
		typedef UnManaged::IDK::ICamera Self;
	public:
		Camera() : Displayable(0), mSelf(0)
		{}
		Camera(Self* self) : Displayable(self), mSelf(self)
		{}
		Self* GetSelf(void) overload { return mSelf; }


		//void SetMoveForce(const Math::Vector3& force)
		//{
		//	mSelf->SetMoveForce(force.GetSelf());
		//}

		void SetPosition(Vector3 pos)
		{
			mSelf->SetPosition(pos.GetSelf());
		}

		void LookAt(Vector3 target)
		{
			mSelf->LookAt(target.GetSelf());
		}

		Vector3 GetPosition(void)
		{
			const UnManaged::System::Math::Vector3& pos = mSelf->GetPosition();
			return Vector3(pos);
		}

		Vector3 GetAbsolutePosition(void)
		{
			UnManaged::System::Math::Vector3 pos = mSelf->GetAbsolutePosition();
			return Vector3(pos);
		}

		Vector3 ScreenToVector(Vector2 xy)
		{
			UnManaged::System::Math::Vector3 retVal = mSelf->ScreenToVector(xy.GetSelf());
			return Vector3(retVal);
		}

		void Rotate(float x, float y)
		{
			mSelf->Rotate(x, y);
		}

		void Update(float dt)
		{
			mSelf->Update(dt);
		}
	private:
		Self* mSelf;
	};

	//BasicCamera
	public ref class BasicCamera : public Camera
	{
		typedef UnManaged::TBasicCamera Self;
	public:
		BasicCamera(void) : Camera(mSelf = new Self())
		{}
		BasicCamera(Self* self) : Camera(self), mSelf(self)
		{}

		Self* GetSelf(void) overload { return mSelf; }
	private:
		Self* mSelf;
	};

	//ThirdPersonCamera
	public ref class ThirdPersonCamera : public BasicCamera
	{
		typedef UnManaged::ThirdPersonCamera Self;
	public:
		ThirdPersonCamera(void) : BasicCamera(mSelf = new Self())
		{}
		ThirdPersonCamera(Self* self) : BasicCamera(self), mSelf(self)
		{}
		Self* GetSelf(void) overload { return mSelf; }

		void LookAt(Vector3 target) overload
		{
			mSelf->LookAt(target.GetSelf());
		}

		void LookAt(Vector3 eye, Vector3 target, Vector3 up)
		{
			mSelf->LookAt(eye.GetSelf(), target.GetSelf(), up.GetSelf());
		}

		void Rotate(float headingDegrees, float pitchDegrees) overload
		{
			mSelf->Rotate(headingDegrees, pitchDegrees);
		}
	private:
		Self* mSelf;
	};

	//Buffer
	public ref class Core : public ManagedObject
	{
		typedef UnManaged::IDK::ICore Self;
	public:
		Core(Self* self) : ManagedObject(mSelf = self)
		{}

		void SetDefaultResourcePath(String^ path)
		{
			StringAdaptor string(path);
			mSelf->SetDefaultResourcePath(string.Get());
		}

		IndexVertexBuffer^ LoadVertexIndexBuffer(String^ path)
		{
			StringAdaptor string(path);
			return gcnew IndexVertexBuffer(mSelf->LoadVertexIndexBuffer(string.Get()).GetUnmanagedPointer());
		}

		Scene^ GetScene(void)
		{
			return gcnew Scene(mSelf->GetScene().GetUnmanagedPointer());
		}

		Mesh^ GetMesh(String^ path)
		{
			StringAdaptor string(path);
			return gcnew Mesh(mSelf->GetMesh(string.Get()).GetUnmanagedPointer());
		}

		Texture^ AddTexture(String^ path,
			Texture::Format fmt,
			Texture::PixelType pixelType,
			unsigned int mipCount,
			unsigned int width,
			unsigned int height)
		{
			StringAdaptor string(path);
			return gcnew Texture(mSelf->AddTexture(string.Get(),
				UnManaged::IDK::ITexture::Format::Enum(fmt),
				UnManaged::IDK::ITexture::PixelType::Enum(pixelType),
				mipCount,
				width,
				height).GetUnmanagedPointer());
		}

		Material^ GetMaterial(String^ name)
		{
			StringAdaptor string(name);
			return gcnew Material(mSelf->GetMaterial(string.Get()).GetUnmanagedPointer());
		}

		SceneObject^ GetSceneObject(String^ name)
		{
			StringAdaptor string(name);
			return ConvertToManaged<SceneObject>(mSelf->GetSceneObject(string.Get()));
		}
		SceneObject^ AddSceneObject(String^ name)
		{
			StringAdaptor string(name);
			return gcnew SceneObject(mSelf->AddSceneObject(string.Get()).GetUnmanagedPointer());
		}

		RenderTarget^ GetRenderTarget(String^ name)
		{
			StringAdaptor string(name);
			return gcnew RenderTarget(mSelf->GetRenderTarget(string.Get()).GetUnmanagedPointer());
		}

		RenderTexture^ CreateRenderTexture(unsigned int width, unsigned int height, Texture::Format fmt, Texture::PixelType pixelType)
		{
			return gcnew RenderTexture(mSelf->CreateRenderTexture(width, height, 
				UnManaged::IDK::ITexture::Format::Enum(fmt),
				UnManaged::IDK::ITexture::PixelType::Enum(pixelType)).GetUnmanagedPointer());
		}

		ShaderProgram^ GetShaderProgram(String^ name)
		{
			StringAdaptor string(name);
			return gcnew ShaderProgram(mSelf->GetShaderProgram(string.Get()).GetUnmanagedPointer());
		}

		void Clear(void)
		{
			mSelf->Clear();
		}
	private:
		Self* mSelf;
	};

	public ref class Viewport : public ManagedObject
	{
		typedef UnManaged::IDK::IViewport Self;
	public:
		Viewport(Self* self) : ManagedObject(mSelf = self)
		{}

		property unsigned int Width
		{
			unsigned int get()
			{
				return mSelf->GetWidth();
			}

			void set(unsigned int value)
			{
				mSelf->SetWidth(value);
			}
		}

		property unsigned int Height
		{
			unsigned int get()
			{
				return mSelf->GetHeight();
			}

			void set(unsigned int value)
			{
				mSelf->SetHeight(value);
			}
		}

		Self* GetSelf(void) overload { return mSelf; }
	private:
		Self* mSelf;
	};

	//Renderer
	public ref class Renderer : public ManagedObject
	{
		typedef UnManaged::IDK::IRenderContext Self;

	public:
		ref class Pass : public ManagedObject
		{
			typedef UnManaged::IDK::IRenderContext::IPass PassSelf;
		public:
			Pass(PassSelf* self) : ManagedObject(mSelf = self)
			{}

			PassSelf* GetSelf(void) overload { return mSelf; }
		private:
			PassSelf* mSelf;
		};

	public:
		Renderer(Self* self) : ManagedObject(mSelf = self)
		{}

		void AddPass(Pass^ pass)
		{
			mSelf->AddPass(pass->GetSelf());
		}

		void ClearPasses(void)
		{
			mSelf->ClearPasses();
		}

		Viewport^ GetViewport()
		{
			return gcnew Viewport(mSelf->GetViewport().GetUnmanagedPointer());
		}

		Viewport^ CreateViewport(unsigned int w, unsigned int h, IntPtr handle)
		{
			return gcnew Viewport(mSelf->CreateViewport(w, h, handle.ToInt32()).GetUnmanagedPointer());
		}

		void SetViewport(Viewport^ viewport)
		{
			if(viewport == nullptr)
			{
				mSelf->SetViewport(UnManaged::System::NullPtr);
			}
			else
			{
				mSelf->SetViewport(viewport->GetSelf());
			}
		}
	private:
		Self* mSelf;
	};

	//Timer
	public ref class Timer : public ManagedObject
	{
	public:
		typedef UnManaged::System::Platform::TimerObject::Instance Self;

		Timer(void) : ManagedObject(mSelf = new Self())
		{
			Start();
		}

		void Start(void)
		{
			mSelf->Start();
		}

		float GetElapsed(void)
		{
			return mSelf->GetElapsed();
		}

		void Sleep(unsigned int timeInMillesecond)
		{
			UnManaged::System::Platform::Time::Sleep(timeInMillesecond);
		}
	private:
		Self* mSelf;
	};

	//Engine
	public ref class Engine : public ManagedObject
	{
		typedef UnManaged::TModuleManager Self;
	public:
		Engine() : ManagedObject(mSelf = new Self())
		{
		}

		void Init(void)
		{
			mSelf->Init();
			//Set Module
			mRenderer = gcnew Renderer(mSelf->GetRenderer().GetUnmanagedPointer());
			mCore = gcnew Core(mSelf->GetCore().GetUnmanagedPointer());
		}

		void Start(void)
		{
			mSelf->Start();
		}

		void Lock(bool reset)
		{
			mSelf->Lock(reset);
		}

		void Unlock(void)
		{
			mSelf->Unlock();
		}

		void Stop(void)
		{
			mSelf->Stop();
		}

		void Update(float dt)
		{
			mSelf->Update(dt);
		}

		Renderer^ GetRenderer(void)
		{
			return mRenderer;
		}
	
		Core^ GetCore(void)
		{
			return mCore;
		}

		void Active(bool value)
		{
			mSelf->Active(value);
		}
	private:
		Renderer^ mRenderer;
		Core^ mCore;
	private:
		Self* mSelf;
	};

	//
	public ref class LightMatrix : public HandlePtr
	{
		typedef UnManaged::Technique::TLightMatrix Self;
	public:
		LightMatrix() : HandlePtr(mSelf = new Self())
		{}
		Self* GetSelf(void) overload { return mSelf; }
	private:
		Self* mSelf;
	};

	//SunShadow
	public ref class SunShadowPass : public Renderer::Pass
	{
		typedef UnManaged::Technique::TSunShadowPass Self;
	public:
		SunShadowPass(
			Scene^ scene,
			Camera^ sunCam,
			Camera^ viewCam,
			ShaderProgram^ programShadow,
			RenderTarget^ shadowRT,
			LightMatrix^ lightMatrix) 
			: Pass( 
			mSelf = new Self(
				scene->GetSelf(),
				sunCam->GetSelf(),
				viewCam->GetSelf(),
				programShadow->GetSelf(),
				shadowRT->GetSelf(),
				lightMatrix->GetSelf())
				)
		{}
	private:
		Self* mSelf;
	};

	//Sun
	public ref class SunCamera : public Camera
	{
		typedef UnManaged::Technique::TSunCamera Self;
	public:
		SunCamera(Camera^ view) : Camera(mSelf = new Self(view->GetSelf()))
		{}
		Self* GetSelf(void) overload { return mSelf; }
	private:
		Self* mSelf;
	};


	//DebugShadingScreenPass
	public ref class DebugShadingScreenPass : public Renderer::Pass
	{
		typedef UnManaged::Technique::TDebugShadingScreenPass Self;
	public:
		DebugShadingScreenPass(RenderTarget^ input, ShaderProgram^ program)
			: Pass(mSelf = new Self(input->GetSelf(), program->GetSelf()))
		{}
		Self* GetSelf(void) overload { return mSelf; }
	private:
		Self* mSelf;
	};

	//DebugShadingPass
	public ref class DebugShadingBufferPass : public Renderer::Pass
	{
		typedef UnManaged::Technique::TDebugShadingBufferPass Self;
	public:
		DebugShadingBufferPass(Scene^ scene, Camera^ cam)
			: Pass(mSelf = new Self(scene->GetSelf(), cam->GetSelf()))
		{}
		Self* GetSelf(void) overload { return mSelf; }
	private:
		Self* mSelf;
	};

	//ForwardShadingPass
	public ref class ForwardShadingPass : public Renderer::Pass
	{
		typedef UnManaged::Technique::TForwardShadingPass Self;
	public:
		ForwardShadingPass(Scene^ scene, Camera^ cam, RenderTarget^ shadow, RenderTarget^ output)
			: Pass(mSelf = new Self(scene->GetSelf(), cam->GetSelf(), shadow->GetSelf(), output->GetSelf()))
		{}
		Self* GetSelf(void) overload { return mSelf; }
	private:
		Self* mSelf;
	};

	//DeferredShadingPass
	public ref class DeferredShadingPass : public Renderer::Pass
	{
		typedef UnManaged::Technique::TDeferredShadingPass Self;
	public:
		DeferredShadingPass(Scene^ scene, Camera^ cam, RenderTarget^ gBuffer, RenderTarget^ shadow, RenderTarget^ output, ShaderProgram^ program)
			: Pass(mSelf = new Self(scene->GetSelf(), cam->GetSelf(), gBuffer->GetSelf(), shadow->GetSelf(), output->GetSelf(), program->GetSelf()))
		{}
		Self* GetSelf(void) overload { return mSelf; }
	private:
		Self* mSelf;
	};

	//OutputScreenShading
	public ref class OutputScreenShadingPass : public Renderer::Pass
	{
		typedef UnManaged::Technique::TOutputScreenPass Self;
	public:
		//
		ref class BlurOffsetParameter : public HandlePtr
		{
			typedef OutputScreenShadingPass::Self::BlurParameter Self;
		public:
			BlurOffsetParameter() : HandlePtr(mSelf = new Self())
			{}
			Self* GetSelf(void) overload { return mSelf; }
		private:
			Self* mSelf;
		};//BlurOffsetParameter

		OutputScreenShadingPass(
			RenderTarget^ output,
			RenderTarget^ temp1,
			RenderTarget^ temp2,
			ShaderProgram^ downProgram,
			ShaderProgram^ highProgram,
			ShaderProgram^ blurProgram,
			ShaderProgram^ finalProgram,
			BlurOffsetParameter^ blurOffsetParameter) 
				: Pass(mSelf = new Self(
					output->GetSelf(),
					temp1->GetSelf(),
					temp2->GetSelf(),
					downProgram->GetSelf(),
					highProgram->GetSelf(),
					blurProgram->GetSelf(),
					finalProgram->GetSelf(),
					blurOffsetParameter->GetSelf()))
		{}
	private:
		Self* mSelf;
	};

	public ref class CoordinateAxes : public Renderable
	{
		typedef UnManaged::Technique::TCoordinateAxes Self;
	public:
		CoordinateAxes() : Renderable(new Self())
		{
		}
	private:
		Self* mSelf;
	};

	public ref class Grid2D : public Renderable
	{
		typedef UnManaged::Technique::TGrid2D Self;
	public:
		Grid2D(ShaderProgram^ shader) : Renderable(new Self(shader->GetSelf()))
		{
		}
	private:
		Self* mSelf;
	};

	public ref class MemoryManager
	{
	public:
		static void Init()
		{
#if defined(DEBUG) | defined(_DEBUG)
			_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
			//_CrtSetBreakAlloc(7146);
#endif
		}

		static void ShowLeaks()
		{
#if defined(DEBUG) | defined(_DEBUG)
			_CrtDumpMemoryLeaks();
#endif
		}
	};
}
